package com.lkdont.android.media.camera

import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.hardware.Camera.PreviewCallback
import com.lkdont.android.base.util.Logger
import java.io.IOException

/**
 * 旧的摄像头工具
 *
 * @author lkdont
 */
@Suppress("DEPRECATION")
class OldCameraManager private constructor() {

    //******************************** 单例模式 ********************************//

    companion object {

        /**
         * CameraManager单例
         */
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            OldCameraManager()
        }

    }

    //************************************************************************//

    private var mCamera: Camera? = null

    /*** 摄像头id */
    var cameraId: Int = -1
        private set

    /**
     * 开启摄像头
     *
     * @param cameraId 摄像头id
     * @return 是否开启成功
     */
    @JvmOverloads
    fun openCamera(cameraId: Int = CameraType.BACK_CAMERA.id): Boolean {
        return try {
            mCamera = Camera.open(cameraId)
            this.cameraId = cameraId
            mCamera!!.setDisplayOrientation(orientation.degrees)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    private val parameters: Camera.Parameters?
        get() {
            if (mCamera == null) {
                Logger.w(this, "还没有开启摄像头")
                return null
            }
            return mCamera!!.parameters
        }

    /*** 预览宽度 */
    val previewWidth: Int
        get() {
            return if (orientation.isLandscape()) {
                // 横屏状态
                parameters?.previewSize?.width ?: 0
            } else {
                // 竖屏状态
                parameters?.previewSize?.height ?: 0
            }
        }

    /*** 预览高度 */
    val previewHeight: Int
        get() {
            return if (orientation.isLandscape()) {
                // 横屏状态
                parameters?.previewSize?.height ?: 0
            } else {
                // 竖屏状态
                parameters?.previewSize?.width ?: 0
            }
        }

    private var mPreviewTexture: SurfaceTexture? = null

    /**
     * 开始预览摄像头界面
     *
     * @param texture 承接预览数据的SurfaceTexture
     * @param callback 预览数据回调
     * @return 是否开启成功
     */
    @JvmOverloads
    fun startPreview(texture: SurfaceTexture, callback: CameraPreviewCallback? = null): Boolean {
        if (mCamera == null) {
            Logger.w(this, "还没有开启摄像头")
            return false
        }
        if (mPreviewTexture != null) {
            if (mPreviewTexture === texture) {
                Logger.w(this, "不允许重复设置预览界面")
                return false
            }
            // 停止当前的预览界面
            stopPreview()
        }
        // 设置预览界面
        return try {
            mCamera!!.setPreviewTexture(texture)
            val previewCallback = getCameraPreviewCallback(callback)
            if (previewCallback != null) {
                val previewSize = mCamera!!.parameters.previewSize
                val previewFormat = mCamera!!.parameters.previewFormat
                Logger.i(
                    this, "startPreview preview width=" + previewSize.width
                            + ", height=" + previewSize.height + ", format=" + previewFormat
                )
                mCamera!!.addCallbackBuffer(
                    createBuffer(previewSize.width, previewSize.height, previewFormat)
                )
                mCamera!!.setPreviewCallbackWithBuffer(previewCallback)
            }
            mCamera!!.startPreview()
            mPreviewTexture = texture
            true
        } catch (e: IOException) {
            e.printStackTrace()
            mPreviewTexture = null
            false
        }
    }

    /**
     * 停止摄像头预览
     */
    fun stopPreview() {
        if (mCamera == null) {
            Logger.w(this, "还没有开启摄像头")
            return
        }
        mCamera!!.stopPreview()
        try {
            mCamera!!.setPreviewCallback(null)
            mCamera!!.setPreviewTexture(null)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        mPreviewTexture = null
    }

    /**
     * 关闭摄像头
     */
    fun closeCamera() {
        if (mCamera == null) {
            Logger.w(this, "还没有开启摄像头")
            return
        }
        // 停止预览
        stopPreview()
        // 取消监听回调
        mCamera!!.setOneShotPreviewCallback(null)
        mCamera!!.setPreviewCallbackWithBuffer(null)
        mCamera!!.addCallbackBuffer(null)
        // 释放摄像头
        mCamera!!.release()
        mCamera = null
        cameraId = -1
        // 重置属性
        orientation = CameraOrientation.DEGREES_0
    }

    /*** 是否已经开启了摄像头 */
    fun isOpened(): Boolean {
        return mCamera != null
    }

    /*** 摄像头的旋转方向 */
    var orientation: CameraOrientation = CameraOrientation.DEGREES_0
        set(value) {
            field = value
            mCamera?.setDisplayOrientation(value.degrees)
        }

    /**
     * 摄像头预览数据回调
     */
    interface CameraPreviewCallback {
        /**
         * 预览数据回调
         *
         * @param data   预览画面数据
         * @param offset 数据开始位置偏移
         * @param len    数据长度
         */
        fun onPreviewFrame(data: ByteArray?, offset: Int, len: Int)
    }

    private fun getCameraPreviewCallback(callback: CameraPreviewCallback?): PreviewCallback? {
        return if (callback == null) {
            null
        } else PreviewCallback { data, _ ->
            callback.onPreviewFrame(data, 0, cameraPreviewBufferSize)
            // 如果在设置预览界面的时候设置了预览数据回调，则需要在回调结束前调用这个方法。
            mCamera?.addCallbackBuffer(data)
        }
    }

    private var cameraPreviewBufferSize = 0

    private fun createBuffer(width: Int, height: Int, format: Int): ByteArray {
        cameraPreviewBufferSize =
            (width * height * (ImageFormat.getBitsPerPixel(format) / 8f)).toInt()
        return ByteArray(cameraPreviewBufferSize)
    }

    //******************************** 子类 ********************************//

    /*** 摄像头角度 */
    enum class CameraOrientation(val degrees: Int) {

        DEGREES_0(0),

        DEGREES_90(90),

        DEGREES_180(180),

        DEGREES_270(270)

        ;

        fun isLandscape(): Boolean {
            return this === DEGREES_0 || this === DEGREES_180
        }

        fun isPortrait(): Boolean {
            return this === DEGREES_90 || this === DEGREES_270
        }
    }

    /*** 摄像头类型 */
    enum class CameraType(val id: Int) {

        BACK_CAMERA(Camera.CameraInfo.CAMERA_FACING_BACK),

        FRONT_CAMERA(Camera.CameraInfo.CAMERA_FACING_FRONT)

    }

}